home *** CD-ROM | disk | FTP | other *** search
- Turbo Pascal for DOS Tutorial
- by Glenn Grotzinger
- Part 12: Stacks and Queues
- copyright(c) 1995-96 by Glenn Grotzinger
-
- Solution to part 11's problem....
-
- program part11; uses dos;
-
- { Lists files and data in a ZIP file. }
-
- type
- ziplocfileheader = record
- zipver: integer;
- bitfield: word;
- compmethod: integer;
- packtime: longint;
- crc32: longint;
- compsize: longint;
- uncompsize: longint;
- filelen: integer;
- xtralen: integer;
- end;
-
- zipcds = record
- ver: byte;
- hostos: byte;
- verxtr: byte;
- targos: byte;
- bitfield: word;
- compmethod: integer;
- packtime: longint;
- crc32: longint;
- compsize: longint;
- uncompsize: longint;
- filelen: integer;
- xtralen: integer;
- comtlen: integer;
- disknum: integer;
- intattr: integer;
- extattr: longint;
- roffset: longint;
- end;
-
- endcdsheader = record
- numdisk: integer;
- numdiska: integer;
- numfiles: integer;
- entries: integer;
- size: longint;
- ofs: longint;
- comtlength: integer;
- end;
-
- var
- zipfile: file;
- outfile: text;
- locfile: ziplocfileheader;
- dirstr: zipcds;
- endcds: endcdsheader;
- filechar: char;
- filelength: array[1..20] of char;
- id: array[1..4] of char;
- i: integer;
- totsize, compsize, uncompsize: longint;
- param1, param2: string;
-
- { Example structure of a ZIP file.
- localheader1
- loccompresseddata1
- localheader2
- loccompresseddata2
- centraldirectorystructure1
- centraldirectorystructure2
- endofcentraldirectorystructure }
-
- procedure readzip;
-
- { ZIP is a random data binary file. We read the ID to check it, then
- differentiate it from there. We also devise a test of whether the
- "ZIP file" is a valid ZIP file here. }
-
- begin
- blockread(zipfile, id, sizeof(id));
- totsize := totsize + 4; { totsize is a seek index }
- if (id[1] <> 'P') and (id[2] <> 'K') then
- begin
- writeln('Corrupted ZIP file, or not a ZIP file.');
- halt(1);
- end;
- case id[3] of
- #05: begin
- blockread(zipfile, endcds, sizeof(endcds));
- totsize := totsize + sizeof(endcds);
- end;
- #03: begin
- blockread(zipfile, locfile, sizeof(locfile));
- totsize := totsize + sizeof(locfile);
- end;
- #01: begin
- blockread(zipfile, dirstr, sizeof(dirstr));
- totsize := totsize + sizeof(dirstr);
- end;
- end;
- end;
-
- function zero(int: integer):string;
- {places zero on the beginning of a number if it's < 10 }
- var
- strng: string;
- numerr: integer;
- begin
- str(int, strng);
- if int < 10 then
- strng := '0' + strng;
- zero := strng;
- end;
-
- function strip(str: string):string;
-
- { removes null characters from random-read filename }
-
- var
- tstr: string;
- i: integer;
- begin
- tstr := '';
- for i := 1 to length(str) do
- if str[i] <> #0 then
- tstr := tstr + str[i];
- strip := tstr;
- end;
-
- function exist(filename: string):boolean;
- { file existence test }
- var
- thefile: text;
- begin
- assign(thefile, filename);
- {$I-}reset(thefile);{$I+}
- if IOResult <> 0 then
- exist := false
- else
- begin
- exist := true;
- close(thefile);
- end;
- end;
-
- procedure header(filename: string);
- { writes header of data }
- var
- s: string;
- begin
- writeln(outfile, 'Files contained in ':41, filename);
- writeln(outfile);
- writeln(outfile, 'NAME', 'COMP-SIZE':21, 'DATE':9,'TIME':12,
- 'UNCOMP-SIZE':15, 'COMP-METHOD':13);
- fillchar(s, 75, '-');
- { fillchar fills a set of contiguous bytes of any type defined by
- the position s is in, for x number of spaces (75), with a char-
- acter represented by - }
- s[0] := #74; { set length byte }
- writeln(outfile, s);
- end;
-
- procedure footer(compsize, uncompsize: longint);
- { write footer of data }
- var
- s: string;
- begin
- fillchar(s, 75, '-');
- s[0] := #74;
- writeln(outfile, s);
- writeln(outfile, compsize:22, uncompsize:34);
- writeln(outfile);
- writeln(outfile, endcds.numfiles, ' files; Effective compression',
- ' ratio: ', (compsize / uncompsize)*100 :0:1, '%');
- end;
-
- procedure writehelp;
- { help for incorrect usage }
- begin
- writeln('ZIPLIST <zipfile> <datafile>');
- halt(1);
- end;
-
- procedure writedata(locfile: ziplocfileheader);
- var
- dt: datetime;
- begin
- unpacktime(locfile.packtime, dt);
- { this handles the MS-DOS time format }
- writeln(outfile, strip(filelength):12, locfile.compsize:10,
- zero(dt.month):7,'-',zero(dt.day),'-',dt.year,
- zero(dt.hour):6,':', zero(dt.min),
- locfile.uncompsize:10, locfile.compmethod:12);
- end;
-
- begin
- if paramcount <> 2 then { incorrect parameters? }
- writehelp;
- totsize := 0;compsize := 0;uncompsize := 0;
- param1 := paramstr(1);
- param2 := paramstr(2);
- assign(zipfile, param1);
- if exist(param1) = false then
- begin
- writeln(param1, ' does not exist!');
- halt(1);
- end;
- reset(zipfile, 1);
- assign(outfile, param2);
- rewrite(outfile);
-
- header(param1);
- readzip;
-
- while id[3] = #03 do
- { process local file headers and compressed data }
- begin
- blockread(zipfile, filelength, locfile.filelen);
- compsize := compsize + locfile.compsize;
- uncompsize := uncompsize + locfile.uncompsize;
- writedata(locfile);
- totsize := totsize + locfile.filelen;
- totsize := totsize + locfile.xtralen;
- fillchar(filelength, sizeof(filelength),#0);
- seek(zipfile, totsize);
- totsize := totsize + locfile.compsize;
- seek(zipfile, totsize);
- readzip;
- end;
-
- while id[3] = #01 do
- { process central directory structure }
- begin
- totsize := totsize + dirstr.filelen;
- seek(zipfile, totsize);
- totsize := totsize + dirstr.xtralen;
- seek(zipfile, totsize);
- readzip;
- end;
-
- footer(compsize, uncompsize);
-
- writeln(outfile);
-
- { handle ZIP comment }
- if endcds.comtlength = 0 then
- writeln(outfile, 'No comment in ZIP file.')
- else
- for i := 1 to endcds.comtlength do
- begin
- blockread(zipfile, filechar, sizeof(filechar));
- write(outfile, filechar);
- end;
-
- close(zipfile);
- close(outfile);
- end.
-
- Hello. Basically, we are dealing in this part with specialized types of
- data structures called stacks and queues.
-
- Stacks
- ======
- A stack is best analagous to a stack of papers on a desk, only able to
- either place a sheet on the top of the stack, or take a sheet off the
- top of the stack. It is generally defined as a record format, which
- can take on the following:
-
- stack = record
- elements: array[1..maxstacksize] of <whatever>;
- capacity: integer; {range of 0..maxstacksize}
- end;
-
- It is best described as a last in/ first out data structure, much like the
- sheet of paper analogy. The elements array holds whatever information
- we need, while capacity tells us how many elements are still in the array.
-
- The best description I can use for this and queues is that it's a limited
- defined access structure.
-
- I will now describe the basic actions of working with stacks. The best
- way to think about coding this is to use the stack of paper as a view-
- point, and using the sample stack record above.
-
- To initialize or effectively kill a stack currently in usage is to set
- capacity to 0. We can do this, because all work with a stack ultimately
- comes down to usage of capacity as an index. If we have 0 sheets of paper
- on an imaginary stack, essentially, the stack is empty.
-
- Now, let's add a sheet of paper to our imaginary stack. We recognize that
- there is one more sheet of paper on the stack now. Then we have to place
- that sheet on the stack...also, we have to keep in mind if we have hit our
- arbitrarily set limit of sheets on the stack, and notify of such thing.
-
- What now, if we have to remove the sheet of paper from our imaginary stack
- of paper? We would need to check if we had a sheet of paper to remove.
- Then after that, we would need to pull the sheet off of the stack, then
- recognize that we removed the sheet.
-
- How do we recognize if we have a full stack or an empty stack? Look at the
- value of capacity. If it's 0, then it's empty. If it's the value for the
- maximum capacity of the stack we decide, then we know it's full.
-
- Basically, in the last four paragraphs, I have, in discussing the actions
- of working with stacks, have given you all the pseudocode you need to
- be able to come up with the code to work with a stack.
-
- It is basically good to develop all of these components as procedures.
- If you come across a problem where a last in, first out solution is
- needed, a stack may be the proper way to go.
-
- Queues
- ======
- A queue is set up much like a line at the local shop to pay the merchant
- at the cash register. The first element in is the first element out.
- Much like a stack, a queue may be defined as a record format.
-
- queue = record
- elements: array[1..maxqueuesize] of <whatever>;
- front, back: integer;
- count: integer;
- end;
-
- Notice that the differences we see here, are that to take from the front
- of the so called line we need to know where the front is in the order.
- The same idea occurs with the back. We need to know where the back is
- in the array. Count just helps us in knowing how many values we currently
- have in the queue.
-
- To start up a queue, basically, we need to start the front at 1, the rear
- at the maximum size, and count at zero.
-
- To check whether it's full or empty is basically set through count. Check
- count to be zero for a queue to be empty and maxsize for a queue to be full.
-
- One sticky mess comes up when we try to add an element to the back of the
- line. How do we keep track of things? We increment the back unless it's
- maxqueuesize, then we set it to 1, essentially, to continue reusing the
- array storage as a loop....
-
- To add to the back of the line, we do like we did with the stack. We add
- the element to the back, then we increment the back count as described
- above.
-
- To take from the front of the line, we pull the element from the front of
- the queue, and then increment the front count as described above.
-
- Basically, the effect we are getting is much like a message scrolling
- across a surface, like you may have seen on your television, and at
- Times Square in NY (on several movies).
-
- Conclusion
- ==========
- Both of these data storage schemes work beautifully, when you have a lot of
- data to deal with that can be passed through quickly, but needs to be
- released at other times...beyond that, at this point, I can't think of
- anything that can be done by only using a stack or a queue, so my
- suggestion for practice is to attempt coding each of these specialized
- data types to do simple things.
-
-
- Practice Programming Problem(s) #12
- ===================================
- Here are a couple of things for this one.
-
- 1) Reverse a string of text inputted from the screen (not necessarily
- a string) of a maximum of 500 characters, and output the text back to
- the screen.
-
- Sample
- ------
- Enter a string: AbCdE
-
- Your string reversed is: EdCbA
-
- 2) Use a queue to store a maximum set of numbers that is 50 numbers long.
- These numbers will come from a series of randomly generated numbers by your
- program. The random numbers you will generate are from 1..1000, and
- the ones that are from 1..50 will be written out to the screen when the
- queue is filled up with those numbers. Write the numbers in the queue out
- in 5 rows of 10, and at the bottom, write out the total number of random
- numbers you had to go through to get those 50 numbers in the proper range.
-
- Sample
- ------
- 23 23 11 22 33 1 9 12 23 11
- 23 3 11 22 33 11 9 12 23 11
- 23 23 11 22 33 11 9 12 23 11
- 23 29 11 2 33 11 9 12 23 11
- 23 23 11 22 33 11 9 50 23 11
-
- 987 numbers were generated from 1-1000 to get the 50 numbers from 1-50.
-
- Next Time
- =========
- Recursion. (n) See Recursion. :>
-
- Any comments? Write ggrotz@2sprint.net.
-